package main

import (
	"fmt"
	"log"
	"runtime"
	"sync"
	"time"
)

type Menu struct {
	Id      int
	Url     string
	Num     int
	SubMenu []Menu
}

const maxRoutineNum = 20

type Sw struct {
	sw *sync.WaitGroup
	ch chan int
}

type MenuService struct {
	MenuList []Menu
	Sw       *Sw
}

func (s *Sw) Add() {
	s.sw.Add(1)
	s.ch <- 1
}
func (s *Sw) Done() {
	s.sw.Done()
	<-s.ch
}

func NewMenuService(param ...interface{}) *MenuService {
	menuS := &MenuService{}
	if len(param) == 1 {
		if ch, ok := param[0].(chan int); ok {
			if cap(ch) > len(ch) {
				menuS.Sw = &Sw{
					sw: &sync.WaitGroup{},
					ch: ch,
				}
			}
		}
	}

	return menuS
}

func (this *MenuService) GetList() []Menu {
	this.MenuList = make([]Menu, 0)

	this.getIdc()

	return this.MenuList
}

func (this *MenuService) getIdc() {

	for i := 0; i < 2; i++ {

		submenu := make([]Menu, 0)

		submenu = append(submenu, this.idcMenu())

		this.MenuList = append(this.MenuList, Menu{Id: i, Url: "", SubMenu: submenu})

	}
	if this.Sw != nil {
		this.Sw.sw.Wait()
	}
}

func (this *MenuService) download(menu *Menu) {

	//不走异步
	if this.Sw == nil {
		// 休眠2秒模拟下载
		time.Sleep(time.Millisecond * 1000)
		menu.Num = menu.Id
	} else {
		this.Sw.Add()
		go func() {
			defer func() {
				if err := recover(); err != nil {
					log.Printf("Work failed with %s", err)
					this.Sw.Done()
				}
			}()
			// 休眠2秒模拟下载
			time.Sleep(time.Millisecond * 1000)

			menu.Num = menu.Id

			this.Sw.Done()
		}()
	}

}

func (this *MenuService) idcMenu() Menu {

	menu := Menu{
		Id:  111,
		Url: "idcMenu",
		SubMenu: []Menu{
			{Id: 1, Url: "http://www.golang.org/1"},
			{Id: 2, Url: "http://www.golang.org/2"},
			{Id: 3, Url: "http://www.golang.org/3"},
			{Id: 4, Url: "http://www.golang.org/4"},
			{Id: 5, Url: "http://www.golang.org/5"},
			{Id: 6, Url: "http://www.golang.org/6"},
			{Id: 7, Url: "http://www.golang.org/7"},
			{Id: 8, Url: "http://www.golang.org/8"},
		},
	}

	for k, _ := range menu.SubMenu {
		switch k {
		case 2:
			this.download(&menu.SubMenu[k])
		case 3:
			this.download(&menu.SubMenu[k])

		default:
			this.download(&menu.SubMenu[k])
		}
	}

	return menu

}

func main() {

	//最多个goroutine 去处理菜单
	ch := make(chan int, 200)
	ch <- 1
	var start = time.Now().Second()

	menuList := NewMenuService(ch).GetList()

	var end = time.Now().Second()
	<-ch
	fmt.Println("时间：", (end - start))

	for k, v := range menuList {
		for _, v1 := range v.SubMenu {
			for k2, v2 := range v1.SubMenu {
				fmt.Printf("[%d/%d]num:%v\n", k, k2, v2.Num)
			}
			fmt.Printf("\n")
		}
	}

	for {
		runtime.Gosched() //主动让出时间片
	}

}
